home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1999 March / EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso / earcd / devel / vbcc-wos-src / pasm / pass.c < prev    next >
C/C++ Source or Header  |  1999-01-01  |  13KB  |  480 lines

  1. /* $VER: pasm pass.c V1.1b (05.07.98)
  2.  *
  3.  * This file is part of pasm, a portable PowerPC assembler.
  4.  * Copyright (c) 1997-98  Frank Wille
  5.  *
  6.  * pasm is freeware and part of the portable and retargetable ANSI C
  7.  * compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
  8.  * pasm may be freely redistributed as long as no modifications are
  9.  * made and nothing is charged for it. Non-commercial usage is allowed
  10.  * without any restrictions.
  11.  * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
  12.  * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
  13.  *
  14.  *
  15.  * v1.1b  (05.07.98) phx
  16.  *        Removed pasm-version symbol.
  17.  * v1.0   (14.04.98) phx
  18.  *        Non-global labels have local binding now. They had none before
  19.  *        and therefore didn't appear in object files.
  20.  * v0.8   (14.02.98) phx
  21.  *        Alignment list for each section. This fixes the problems
  22.  *        with optimizations.
  23.  * v0.7   (02.01.98) phx
  24.  *        Allow more than two assembler passes, as required for
  25.  *        optimizations.
  26.  * v0.6   (26.10.97) phx
  27.  *        Bug in conditional assembly fixed.
  28.  *        @object and @function symbols are always defined before
  29.  *        pass 1 is executed.
  30.  * v0.5   (12.10.97) phx
  31.  *        Support for user symbol definitions by -D option.
  32.  *        The opcode field is automatically converted to lower case,
  33.  *        so upper case directives and instructions are also allowed.
  34.  * v0.3   (10.04.97) phx
  35.  *        Some vbcc-specific changes.
  36.  * v0.2   (25.03.97) phx
  37.  *        Writes ELF object for 32-bit PowerPC big-endian. Either absolute
  38.  *        or ELF output format may be selected. ELF is default for all
  39.  *        currently supported platforms. PPCasm supports nine different
  40.  *        relocation types (there are much more...).
  41.  *        Compiles and works also under NetBSD/amiga (68k).
  42.  *        Changed function declaration to 'new style' in all sources
  43.  *        (to avoid problems with '...' for example).
  44.  * v0.1   (11.03.97) phx
  45.  *        First test version with all PowerPC instructions and most
  46.  *        important directives. Only raw, absolute output.
  47.  * v0.0   (15.02.97) phx
  48.  *        File created.
  49.  */
  50.  
  51.  
  52. #define PASS_C
  53. #include "ppcasm.h"
  54.  
  55.  
  56. void exec_pass1(struct GlobalVars *);
  57. void pass1(struct GlobalVars *,struct SourceText *,
  58.            struct MacroParams *,struct SourceThread *);
  59. struct SourceText *include_source(struct GlobalVars *,char *);
  60. void exec_pass2(struct GlobalVars *);
  61. void pass2(struct GlobalVars *,struct SourceText *,
  62.            struct MacroParams *,struct SourceThread *);
  63. struct SourceText *get_source(struct GlobalVars *);
  64.  
  65. static char *insert_macro_params(struct GlobalVars *,struct ParsedLine *,
  66.                                  char *,struct MacroParams *);
  67. static char *readline(struct GlobalVars *,struct ParsedLine *,char *);
  68. static char *getlabel(struct GlobalVars *,char *);
  69. static struct SourceText *add_source(struct GlobalVars *,char *,char *,long);
  70. static void prepare_sections(struct GlobalVars *);
  71.  
  72.  
  73.  
  74. void exec_pass1(struct GlobalVars *gv)
  75. {
  76.   struct Symbol *sym;
  77.   char **p,*xmnemobuf,*usrdefbuf;
  78.   size_t xmsize=0,udsize=0;
  79.   struct UserDefine *nextudn;
  80.   struct UserDefine *udn = (struct UserDefine *)gv->userdeflist.first;
  81.   struct Section dummySec;
  82.  
  83.   memset(&dummySec,0,sizeof(struct Section));
  84.   gv->csect = &dummySec;  /* to avoid SEGVs during start up */
  85.   gv->lcsym = add_symbol(gv,"$",SYM_RELOC,0);
  86.   gv->nargsym = add_symbol(gv,"$NARG",SYM_ABS,0);
  87.   add_symbol(gv,"@object",SYM_ABS,1);
  88.   add_symbol(gv,"@function",SYM_ABS,2);
  89.   gv->ifcond[0] = TRUE;
  90.  
  91.   pass1(gv,add_source(gv,"<standard sections>",stdsects,
  92.         strlen(stdsects)),NULL,NULL);
  93.  
  94.   if (!gv->noregsymbols)
  95.     pass1(gv,add_source(gv,"<standard definitions>",stdsets,
  96.           strlen(stdsets)),NULL,NULL);
  97.  
  98.   while (nextudn = (struct UserDefine *)udn->n.next) {
  99.     udsize += strlen(udn->line);
  100.     udn = nextudn;
  101.   }
  102.   if (udsize) {
  103.     usrdefbuf = alloc(udsize+1);
  104.     *usrdefbuf = 0;
  105.     while (udn = (struct UserDefine *)remhead(&gv->userdeflist)) {
  106.       strcat(usrdefbuf,udn->line);
  107.       free(udn->line);
  108.       free(udn);
  109.     }
  110.     gv->usrdefs = TRUE;
  111.     pass1(gv,add_source(gv,"<user definitions>",usrdefbuf,udsize),
  112.           NULL,NULL);
  113.   }
  114.  
  115.   if (!gv->noextmnemo) {
  116.     p = xmnemos;
  117.     while (*p) {
  118.       xmsize += strlen(*p);
  119.       p++;
  120.     }
  121.     xmnemobuf = alloc(xmsize+1);
  122.     *xmnemobuf = 0;
  123.     p = xmnemos;
  124.     while (*p) {
  125.       strcat(xmnemobuf,*p);
  126.       p++;
  127.     }
  128.     pass1(gv,add_source(gv,"<extended mnemonics>",xmnemobuf,xmsize),
  129.           NULL,NULL);
  130.   }
  131.  
  132.   pass1(gv,include_source(gv,gv->source_name),NULL,NULL);
  133.   if (gv->vc) {
  134.     activate_section(gv,(struct Section *)gv->sectionlist.first);
  135.     alignment(gv,2);
  136.     pcadd(gv,4);
  137.   }
  138. }
  139.  
  140.  
  141. void pass1(struct GlobalVars *gv,struct SourceText *srctxt,
  142.            struct MacroParams *macro,struct SourceThread *prev_st)
  143. /* Assembler Pass 1 */
  144. {
  145.   struct SourceThread st;
  146.   unsigned long nlines = srctxt->nlines;
  147.   char *lp,c;
  148.   struct ParsedLine *pl = srctxt->plin;
  149.  
  150.   /* init SourceThread structure */
  151.   st.prev = prev_st;
  152.   st.macro = macro;
  153.   st.csource = srctxt;
  154.   st.srcptr = srctxt->text;  /* current source pointer */
  155.   st.line = 1;
  156.   st.macskip = NULL;
  157.   gv->cthread = &st;  /* set current source thread */
  158.  
  159.   while (nlines--) {
  160.     gv->absline++;
  161.     pl->lineptr = st.lineptr = st.srcptr;
  162.  
  163.     /* get next line of source text */
  164.     if (macro && gv->ifcond[gv->iflevel]) {  /* insert macro parameters? */
  165.       st.srcptr = insert_macro_params(gv,pl,st.srcptr,macro);
  166.     }
  167.     else {
  168.       st.srcptr = readline(gv,pl,st.srcptr);
  169.     }
  170.     lp = gv->linebuf;
  171.  
  172.     /* evaluate label field */
  173.     lp = getlabel(gv,lp);
  174.     if (*gv->strbuf)
  175.       if (!st.macskip && gv->ifcond[gv->iflevel]) {
  176.         struct Symbol *sym;
  177.         sym = add_symbol(gv,gv->strbuf,SYM_RELOC,gv->csect->pc);
  178.         if (!sym->bind)
  179.           /* labels have always local binding first */
  180.           sym->bind = SYMB_LOCAL;
  181.       }
  182.     lp = skipspaces(lp);
  183.  
  184.     /* evaluate opcode field */
  185.     lp = getsymbol(gv,lp);
  186.     if (*gv->strbuf) {
  187.       lower_case(gv->strbuf);  /* convert opcode to lower case */
  188.  
  189.       if (st.macskip) {  /* macros */
  190.         if (!strcmp(gv->strbuf,".endm")) {
  191.           st.macskip->nlines = gv->absline - st.macskip->nlines;
  192.           add_macro(gv,st.macskip);
  193.           st.macskip = NULL;
  194.         }
  195.       }
  196.  
  197.       else if (!gv->ifcond[gv->iflevel]) {  /* conditional assembly */
  198.         if (!strncmp(gv->strbuf,".if",3))
  199.           gv->ifignore++;
  200.         else if (!strcmp(gv->strbuf,".else")) {
  201.           if (gv->ifignore == 0)
  202.             gv->ifcond[gv->iflevel] = TRUE;
  203.         }
  204.         else if (!strcmp(gv->strbuf,".endif")) {
  205.           if (gv->ifignore)
  206.             gv->ifignore--;
  207.           else
  208.             gv->iflevel--;
  209.         }
  210.       }
  211.  
  212.       else {  /* search opcode */
  213.         c = *lp;  /* branch hint given? */
  214.         if (c=='+') {
  215.           lp++;
  216.           pl->branch_hint = 1;
  217.         }
  218.         else if (c=='-') {
  219.           lp++;
  220.           pl->branch_hint = -1;
  221.         }
  222.         search_opcode(gv,pl,gv->strbuf,skipspaces(lp));
  223.       }
  224.     }
  225.  
  226.     if (!(pl->flags&PLF_NONEWLINE))
  227.       st.line++;
  228.     ++pl;
  229.   }
  230.   gv->cthread = prev_st;
  231. }
  232.  
  233.  
  234. static char *insert_macro_params(struct GlobalVars *gv,struct ParsedLine *pl,
  235.                                  char *s,struct MacroParams *mp)
  236. {
  237.   char **par = mp->param;
  238.   char c,callidbuf[16];
  239.   char *pp,*d=gv->linebuf;
  240.   int n;
  241.  
  242.   do {
  243.     if ((c=*s++) == '\\') {
  244.       if (*s>='0' && *s<='9') {  /* macro parameter? */
  245.         n = (int)(*s++ - '0');
  246.         if (pp = par[n]) {
  247.           while (*d++ = *pp++);  /* insert parameter */
  248.           d--;
  249.           continue;
  250.         }
  251.         else {
  252.           error(9,n);  /* reference to undefined macro parameter n */
  253.           continue;
  254.         }
  255.       }
  256.       else if (*s=='@') {  /* insert macro call id */
  257.         s++;
  258.         pp = callidbuf;
  259.         sprintf(pp,"$%d",(int)mp->call_id);
  260.         while (*d++ = *pp++);
  261.         d--;
  262.         continue;
  263.       }
  264.     }
  265.     *d++ = c;
  266.   }
  267.   while (c!=0 && c!=1);
  268.   if (c==1) {
  269.     *(--d) = 0;
  270.     pl->flags |= PLF_NONEWLINE;
  271.   }
  272.   return (s);
  273. }
  274.  
  275.  
  276. static char *readline(struct GlobalVars *gv,struct ParsedLine *pl,char *s)
  277. {
  278.   char c,*d = gv->linebuf;
  279.  
  280.   do {
  281.     c = *s++;
  282.     *d++ = c;
  283.   }
  284.   while (c!=0 && c!=1);
  285.   if (c==1) {
  286.     *(--d) = 0;
  287.     pl->flags |= PLF_NONEWLINE;
  288.   }
  289.   return (s);
  290. }
  291.  
  292.  
  293. static char *getlabel(struct GlobalVars *gv,char *s)
  294. /* read label to gv->strbuf, s points to the beginning of a line */
  295. {
  296.   char *s_old = s;
  297.  
  298.   s = getsymbol(gv,s);  /* read label to buffer */
  299.   if ((s != s_old) && (*s == ':'))  /* colon indicates a valid label */
  300.     return (++s);
  301.   *gv->strbuf = 0;
  302.   return (s_old);
  303. }
  304.  
  305.  
  306. struct SourceText *include_source(struct GlobalVars *gv,char *name)
  307. /* called when encountering an .include directive */
  308. {
  309.   char *s = mapfile(gv,name);
  310.   long len = *(size_t *)(s - sizeof(size_t));  /* mapfile stores size here */
  311.  
  312.   return (add_source(gv,name,s,len));
  313. }
  314.  
  315.  
  316. static struct SourceText *add_source(struct GlobalVars *gv,char *name,
  317.                                      char *s,  /* source text pointer */
  318.                                      long len) /* text length in bytes */
  319. /* create a new SourceText node and add it to the source list */
  320. {
  321.   struct SourceText *stxt = alloc(sizeof(struct SourceText));
  322.   bool comm=FALSE;
  323.   char quote=0;
  324.  
  325.   stxt->name = name;
  326.   stxt->text = s;
  327.   stxt->nlines = 0;
  328.  
  329.   /* replace '\n' and ';' by \0 and determine number of lines */
  330.   for (; len>0; len--,s++) {
  331.     switch (*s) {
  332.       case '\n':
  333.         *s = 0;
  334.         stxt->nlines++;
  335.         comm = FALSE;  /* \n ends a comment */
  336.         break;
  337.       case '\r':  /* ignore CRs */
  338.         *s = 0;
  339.         break;
  340.       case ';':   /* ';' allows multiple statements per line */
  341.         if (!comm && !quote) {
  342.           if (*(s+1)=='\n' || *(s+1)=='\r')
  343.             *s = ' ';
  344.           else {
  345.             *s = 1;
  346.             stxt->nlines++;
  347.           }
  348.         }
  349.         break;
  350.       case '#':   /* comment: ignore ';' in rest of line */
  351.         comm = TRUE;
  352.         break;
  353.       case 0x22:  /* ignore ';' in strings too */
  354.         if (quote==0x22)
  355.           quote = 0;
  356.         else if (!quote)
  357.           quote = 0x22;
  358.         break;
  359.       case 0x27:
  360.         if (quote==0x27)
  361.           quote = 0;
  362.         else if (!quote)
  363.           quote = 0x27;
  364.         break;
  365.     }
  366.   }
  367.  
  368.   stxt->plin = alloczero(stxt->nlines * sizeof(struct ParsedLine));
  369.   addtail(&gv->sourcelist,&stxt->n);
  370.   return (stxt);
  371. }
  372.  
  373.  
  374. static void prepare_sections(struct GlobalVars *gv)
  375. /* prepare sections for receiving code in pass 2 */
  376. {
  377.   struct Section *nexts,*sec=(struct Section *)gv->sectionlist.first;
  378.  
  379.   while (nexts = (struct Section *)sec->n.next) {
  380.     sec->size = sec->pc;
  381.     sec->pc = 0;
  382.     sec->current_align = sec->first_align;
  383.     if (!(sec->flags & SF_UNINITIALIZED))
  384.       if (sec->size)
  385.         sec->data = sec->contents = alloc((size_t)sec->size);
  386.     sec = nexts;
  387.   }
  388. }
  389.  
  390.  
  391. void exec_pass2(struct GlobalVars *gv)
  392. {
  393.   gv->absline = 0;
  394.   gv->pass++;
  395.   prepare_sections(gv);
  396.   gv->srctxtp = (struct SourceText *)gv->sourcelist.first;
  397.  
  398.   pass2(gv,get_source(gv),NULL,NULL);  /* <standard sections> */
  399.   if (!gv->noregsymbols)
  400.     pass2(gv,get_source(gv),NULL,NULL);  /* <standard definitions> */
  401.   if (gv->usrdefs)
  402.     pass2(gv,get_source(gv),NULL,NULL);  /* <user definitions> */
  403.   if (!gv->noextmnemo)
  404.     pass2(gv,get_source(gv),NULL,NULL);  /* <extended mnemonics> */
  405.  
  406.   pass2(gv,get_source(gv),NULL,NULL); 
  407.   if (gv->vc) {
  408.     activate_section(gv,(struct Section *)gv->sectionlist.first);
  409.     alignment(gv,2);
  410.     store_word(gv,0x76626363);
  411.   }
  412. }
  413.  
  414.  
  415. void pass2(struct GlobalVars *gv,struct SourceText *srctxt,
  416.            struct MacroParams *macro,struct SourceThread *prev_st)
  417. /* Assembler Pass 2 */
  418. {
  419.   struct SourceThread st;
  420.   unsigned long nlines = srctxt->nlines;
  421.   struct ParsedLine *pl = srctxt->plin;
  422.   struct ParsedLine *p;
  423.   uint32 oldnarg;
  424.  
  425.   /* init SourceThread structure */
  426.   st.prev = prev_st;
  427.   st.macro = macro;
  428.   st.csource = srctxt;
  429.   st.line = 1;
  430.   gv->cthread = &st;  /* set current source thread */
  431.  
  432.   while (nlines--) {
  433.     gv->absline++;
  434.     st.lineptr = pl->lineptr;
  435.     p = pl;
  436.  
  437.     do {
  438.       /* evaluate opcode field */
  439.       switch (p->type) {
  440.  
  441.         case OT_INSTRUCTION:
  442.           instr(gv,p);
  443.           break;
  444.  
  445.         case OT_DIRECTIVE:
  446.           (((struct Directive *)p->opcode)->dfunct)(gv,p);
  447.           break;
  448.  
  449.         case OT_MACRO:
  450.           oldnarg = gv->nargsym->value;
  451.           gv->nargsym->value = (uint32)p->narg;
  452.           pass2(gv,get_source(gv),(struct MacroParams *)gv,gv->cthread);
  453.           /* the MacroParams pointer is set to gv, because we */
  454.           /* only need a non-zero pointer here... */
  455.           gv->nargsym->value = oldnarg;
  456.           break;
  457.  
  458.         case OT_SECTION:
  459.           activate_section(gv,(struct Section *)p->opcode);
  460.           break;
  461.       }
  462.     }
  463.     while (p = p->next);
  464.  
  465.     if (!(pl->flags&PLF_NONEWLINE))
  466.       st.line++;
  467.     ++pl;
  468.   }
  469.   gv->cthread = prev_st;
  470. }
  471.  
  472.  
  473. struct SourceText *get_source(struct GlobalVars *gv)
  474. {
  475.   struct SourceText *st = gv->srctxtp;
  476.  
  477.   gv->srctxtp = (struct SourceText *)st->n.next;
  478.   return (st);
  479. }
  480.